package com.cskaoyan.javase.oop2._1extends._8hidden;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 继承中的属性隐藏
 * 在这一小节,我们主要探究"对象名.成员变量名"的访问机制
 *
 * 引例:
 * 在上面章节中，我们已经知道，父子类的成员是允许同名的。
 * 那么如果父子类属性同名了，那么不使用super区分，直接访问的效果是什么样的呢？
 *
 * 现在我们直接创建子类对象，使用子类引用接收,访问父子类同名成员变量
 * 会发现访问的结果是子类中属性的取值，那么父类中的那个同名成员变量去哪了呢？
 *
 * 首先它存在吗?
 * 父子类成员变量有各自的存储区域,所以它们都是存在的
 * 那么为什么访问的结果是子类中的取值,而不是父类中属性的取值呢?
 * 这个原因是因为被覆盖了吗?还是因为特殊的访问机制,而被隐藏了呢?
 * 通过父类的Getter方法,显然还可以继续访问父类同名成员变量,所以它不是覆盖,只是因为特殊的访问机制被隐藏了,这就是属性的隐藏.
 *
 * 那这种特殊的访问机制是什么呢?我们接下来重点研究这个访问机制.
 * "对象名.成员变量名"的访问机制,从两个角度来研究它的访问机制:
 *      1.访问的范围,"对象名."能够访问哪些成员变量
 *      2.访问的结果,"对象名."访问一个成员变量,它的结果是什么
 *
 * 在存在继承父子类的前提下,创建对象的方式有几种?(因为既然是对象名点访问,那么首先需要创建对象,然后用引用接收)
 *      1.创建父类对象,用父类引用接收
 *      2.创建子类对象,用子类引用接收
 *      3.创建子类对象,用父类引用接收
 *
 * 接下来首先研究"对象名.成员变量"访问范围:
 *      1.创建父类对象,用父类引用接收
 *          访问范围就只有父类自身
 *
 *      2.创建子类对象,用子类引用接收
 *          访问范围是父类 + 子类
 *
 *      3.创建子类对象,用父类引用接收
 *          访问范围就只有父类
 *
 *      以上总结,"对象名.成员变量"
 *      它的访问范围由引用的数据类型来决定:
 *      a.如果引用是父类,那么访问范围就只有父类
 *      a.如果引用是子类,那么访问范围就是子类 + 父类
 *
 * 扩展:
 *      1.对应创建对象的语句来说,左边是声明这个引用数据类型的引用的类型,它是声明
 *      声明的意义是告诉编译编译器,这个变量的数据类型
 *
 *      而访问范围是一个编译上的概念,由编译器进行语法检查
 *      引用的数据类型对于编译器来说,就代表了这个引用数据类型的类型,所以访问范围只需要看引用的数据类型就可以了
 *
 *      2.在编译器确定访问访问的时候,它的一个检索机制是什么样的?
 *      先从自身类中去找该成员,如果找不到去父类中找
 *      直到找到最顶层祖先类Object
 *      如果还没有找到,就会编译报错
 *
 *      这个检索,有可能找子类吗?
 *      不可能
 *      "对于Java代码而言,一个子类是明确知道它的父类是谁,且有几个(因为extends关键字明确声明了)但是一个父类,是不知道它有子类的,更不知道它有几个子类"
 *
 *
 * 最后研究"对象名.成员变量名"的访问结果
 *      1.创建父类对象,用父类引用接收
 *          访问结果必然是父类决定
 *          结果是父类中的结果
 *
 *      2.创建子类对象,用子类引用接收
 *          访问结果必然是子类决定
 *          结果是子类中的结果
 *
 *      3.创建子类对象,用父类引用接收
 *          访问结果是父类中的结果
 *
 * 以上,总结,"对象名.成员变量名"的访问结果是由引用的数据类型来决定的,引用所在类型中该成员变量的取值就是访问的结果.
 *
 * 最后,综合对象名点访问成员变量的范围和结果
 * 发现：
 * 都是根据引用的数据类型来决定的，无需考虑是何种对象。
 *
 * @since 11:29
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        /*Son s = new Son();
        System.out.println(s.num);
        System.out.println(s.getNum());*/

        //  1.创建父类对象,用父类引用接收
        Father f = new Father();
        System.out.println("f.num = " + f.num);

        //  2.创建子类对象,用子类引用接收
        Son s = new Son();
        System.out.println("s.num = " + s.num);

        System.out.print("子类对象使用super访问父类同名成员变量:");
        s.superAccessFatherNum();

        //  3.创建子类对象,用父类引用接收
        Father fs = new Son();
        // System.out.println(fs.num);
        // System.out.println(fs.fatherNum);
        // fs强转后能够访问子类成员,但原本是不能直接访问的
        // ((Son) fs).sonNum
        System.out.println("fs.num = " + fs.num);
    }
}

class Father {
    int num = 10;
    // 独属于父类的成员变量
    int fatherNum = 100;

    // public int getNum() {
    //     return num;
    // }
}

class Son extends Father {
    int num = 20;
    // 独属于子类的成员变量
    int sonNum = 200;

    public void superAccessFatherNum(){
        System.out.println(super.num);
    }
}